/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/commons/json/util/ThreadLocalCache.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: ThreadLocalCache.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (Mon, 02 Jul 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.commons.json.util;

import java.lang.ref.SoftReference;
import java.nio.charset.CharsetDecoder;

public class ThreadLocalCache {

	public final static int CHARS_CACH_INIT_SIZE = 1024; // 1k;
	public final static int CHARS_CACH_MAX_SIZE = 1024 * 128; // 1k;
	private final static ThreadLocal<SoftReference<char[]>> charsBufLocal = new ThreadLocal<SoftReference<char[]>>();

	private final static ThreadLocal<CharsetDecoder> decoderLocal = new ThreadLocal<CharsetDecoder>();

	public static CharsetDecoder getUTF8Decoder() {
		CharsetDecoder decoder = decoderLocal.get();
		if (decoder == null) {
			decoder = new UTF8Decoder();
			decoderLocal.set(decoder);
		}
		return decoder;
	}

	public static void clearChars() {
		charsBufLocal.set(null);
	}

	public static char[] getChars(int length) {
		final SoftReference<char[]> ref = charsBufLocal.get();

		if (ref == null) {
			return allocate(length);
		}

		char[] chars = ref.get();

		if (chars == null) {
			return allocate(length);
		}

		if (chars.length < length) {
			chars = allocate(length);
		}

		return chars;
	}

	private static char[] allocate(int length) {
		final int allocateLength = getAllocateLength(CHARS_CACH_INIT_SIZE, CHARS_CACH_MAX_SIZE, length);

		if (allocateLength <= CHARS_CACH_MAX_SIZE) {
			final char[] chars = new char[allocateLength];
			charsBufLocal.set(new SoftReference<char[]>(chars));
			return chars;
		}

		return new char[length];
	}

	private static int getAllocateLength(int init, int max, int length) {
		int value = init;
		for (;;) {
			if (value >= length) {
				return value;
			}

			value *= 2;

			if (value > max) {
				break;
			}
		}

		return length;
	}

	// /////////
	public final static int BYTES_CACH_INIT_SIZE = 1024; // 1k;
	public final static int BYTeS_CACH_MAX_SIZE = 1024 * 128; // 1k;
	private final static ThreadLocal<SoftReference<byte[]>> bytesBufLocal = new ThreadLocal<SoftReference<byte[]>>();

	public static void clearBytes() {
		bytesBufLocal.set(null);
	}

	public static byte[] getBytes(int length) {
		final SoftReference<byte[]> ref = bytesBufLocal.get();

		if (ref == null) {
			return allocateBytes(length);
		}

		byte[] bytes = ref.get();

		if (bytes == null) {
			return allocateBytes(length);
		}

		if (bytes.length < length) {
			bytes = allocateBytes(length);
		}

		return bytes;
	}

	private static byte[] allocateBytes(int length) {
		final int allocateLength = getAllocateLength(CHARS_CACH_INIT_SIZE, CHARS_CACH_MAX_SIZE, length);

		if (allocateLength <= CHARS_CACH_MAX_SIZE) {
			final byte[] chars = new byte[allocateLength];
			bytesBufLocal.set(new SoftReference<byte[]>(chars));
			return chars;
		}

		return new byte[length];
	}

}
